#pragma once

#include <iostream>
#include <unistd.h>
#include <vector>
#include <semaphore.h>

const static int defaultcapacity = 5;
template <class T>
class RingQueue
{
private:
    //信号量是OS中用于进程/线程同步的机制，核心是“计数器+等待队列”
    //--
    void P(sem_t &sem)
    {
        //P操作，尝试获取资源，若信号量计数>0,计数器--，若==0，当前进程/线程阻塞，直到有信号可用
        sem_wait(&sem);
    }
    //++
    void V(sem_t &sem)
    {
        //信号量V操作，释放资源，信号量计数+1，若有阻塞的线程/进程，唤醒其中一个
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }

    void Unlock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int cap = defaultcapacity)
        : ringqueue(cap), capacity(cap), c_step(0), p_step(0)
    {
        sem_init(&c_data_sem, 0, 0);
        sem_init(&p_space_sem, 0, capacity);

        pthread_mutex_init(&c_mutex, 0);
        pthread_mutex_init(&p_mutex, 0);
    }

    void Pop(T*out) //消费
    {
        P(c_data_sem);
        Lock(c_mutex);
        *out=ringqueue[c_step];
        c_step++;
        c_step%=capacity;
        Unlock(c_mutex);
        V(p_space_sem);
    }

    void Push(const T&in) //生产
    {
        P(p_space_sem);
        Lock(p_mutex);
        ringqueue[p_step]=in;
        p_step++;
        p_step%=capacity;
        Unlock(p_mutex);
        V(c_data_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&c_data_sem);
        sem_destroy(&p_space_sem);
        pthread_mutex_destroy(&c_mutex);
        pthread_mutex_destroy(&p_mutex);
    }

private:
    // 利用数组来模拟环形队列
    std::vector<T> ringqueue;
    int capacity;      // 容量
    int c_step;        // 消费者的下标
    int p_step;        // 生产者的下标
    //信号量主要用来协助线程间的资源状态-是否可用？
    //实现线程的同步+解耦
    sem_t c_data_sem;  // 消费者关注的数据资源
    sem_t p_space_sem; // 生产者关注的空间资源
    // 消费者和生产者各一把锁
    pthread_mutex_t c_mutex;
    pthread_mutex_t p_mutex;
};